package de.fhaugsburg.games.boardgames.scrabble.terminal;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

public class TerminalServer {

	
	private int maxPlayers;
	private int nextFreeTerminalId = 1;
	private Hashtable<Integer, Integer> playersTerminalId = new Hashtable<Integer, Integer>(); 
	private List<Integer> allTerminals;
	

	public TerminalServer(int maxPlayers) {
		this.maxPlayers = maxPlayers;
		resetTerminalServer();
	}

	
	/**
	 * cleanup temp files
	 */
	protected void finalize() throws Throwable{
		cleanupTerminalFiles();
		super.finalize();
	}
	
	
	/**
	 * resets all terminal slots
	 */
	public void resetTerminalServer(){
		this.nextFreeTerminalId = 1;
		cleanupTerminalFiles();
	}
	
	


	/**
	 * cleanup all files used for terminal communication
	 */
	private void cleanupTerminalFiles(){
		File serverDir = new File(TerminalUtils.MSG_DIR);
		File[] tempFiles = serverDir.listFiles();
		for (File tempFile : tempFiles){
			if (tempFile.getAbsolutePath().startsWith(TerminalUtils.INPUT_REQUEST)
				|| tempFile.getAbsolutePath().startsWith(TerminalUtils.INPUT_RESPONSE)
				|| tempFile.getAbsolutePath().startsWith(TerminalUtils.SERVER_MSG)){
//				System.out.println(tempFile.getAbsolutePath());
				tempFile.delete();
			}
		}
	}
	
	
	
	/**
	 * get next free terminal slot
	 * @return
	 */
	private int getNextFreeTerminalId(){
		return nextFreeTerminalId;
	}
	
	
	
	
	/**
	 * adds a new terminal slot
	 * @return id of the new terminal
	 */
	public int addNewTerminalSlot(){
		int id = getNextFreeTerminalId();
		sendRequest(id, id + TerminalUtils.FREE_TERMINAL_SLOT);
		nextFreeTerminalId++;
		return id;
	}
	
	

	/**
	 * reads all answers to the initial addNewTermialSlot request and returns IDs as list
	 * @return
	 */
	public List<Integer> getAnsweringTerminals(){
		List<Integer> terminalIds = new ArrayList<Integer>();
		
		File serverDir = new File(TerminalUtils.MSG_DIR);
		File[] tempFiles = serverDir.listFiles();
		for (File tempFile : tempFiles){
			if (tempFile.getAbsolutePath().startsWith(TerminalUtils.INPUT_RESPONSE)){
				String answer = "";
				try {
					answer = TerminalUtils.readFile(tempFile).trim();
					if (answer.endsWith(TerminalUtils.FREE_TERMINAL_SLOT)){
						tempFile.delete();
						terminalIds.add(Integer.parseInt(answer.substring(0, 1)));
					}
				} catch (IOException e) {
					//ignore this terminal
				}
			}
		}
		allTerminals = terminalIds;
		return terminalIds;
	}
	
	
	
	
	/**
	 * send message to a terminal
	 * @param msg
	 * @param id
	 */
	public void sendMessage(String msg, int id){
		File fTmp = new File(TerminalUtils.SERVER_MSG + id);
		try {
			TerminalUtils.writeFile(fTmp, msg);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * send message to a list of terminals
	 * @param msg
	 * @param terminalIds
	 */
	public void sendMessage(String msg, List<Integer> terminalIds){
		for (Integer id : terminalIds) {
			sendMessage(msg, id);
		}
	}
	
	
	
	/**
	 * sends message to all known/connected terminals
	 * @param msg
	 */
	public void sendMessageToAll(String msg){
		sendMessage(msg, allTerminals);
	}
	
	
	
	
	/**
	 * just write a request
	 * @param id
	 * @param request
	 */
	public void sendRequest(int id, String request){
		// write input request
		File fTmp = new File(TerminalUtils.INPUT_REQUEST + id);
		try {
			TerminalUtils.writeFile(fTmp, request);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	
	
	/**
	 * reads command from a terminal
	 * @param id
	 * @param request
	 * @return
	 * @throws InterruptedException 
	 */
	public String getInputLine(int id, String request) throws InterruptedException{
		
		sendRequest(id, request);
		
		// wait for input response, and read
		File fTmp = new File(TerminalUtils.INPUT_RESPONSE + id);
		while (!fTmp.exists()) {
			Thread.sleep(250);
		}
		
		// read input response
		try {
			// read
			String sTmp = TerminalUtils.readFile(fTmp);
			// delete 
			fTmp.delete();
			return sTmp;			
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	
	
	
	/**
	 * maps player-ID to terminal-ID
	 * @param playerId
	 * @param terminalId
	 */
	public void setPlayersTerminal(int playerId, int terminalId){
		playersTerminalId.put(playerId, terminalId);
	}


	/**
	 * get terminal-ID for given player
	 * @param playerId
	 * @return
	 */
	public int getPlayersTerminal(int playerId){
		return playersTerminalId.get(playerId);
	}
	
	
	


	/**
	 * @return the maxPlayers
	 */
	public int getMaxPlayers() {
		return maxPlayers;
	}
	
	
}
